package com.common.base.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.common.base.utils.WeakHandler;

public class MyRecyclerView extends RecyclerView {

    private boolean autoRecycle = false;
    private final WeakHandler handler = new WeakHandler();

    public MyRecyclerView(Context context) {
        this(context, null);
    }

    public MyRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    public void setAutoRecycle(boolean bo) {
        autoRecycle = bo;
    }

    @Override
    public void setLayoutManager(LayoutManager layout) {
        if (getLayoutManager() == layout) {
            return;
        }
        if (autoRecycle && layout instanceof LinearLayoutManager) {
            ((LinearLayoutManager) layout).setRecycleChildrenOnDetach(true);
        }
        super.setLayoutManager(layout);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        try {
            super.onLayout(changed, l, t, r, b);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean drawChild(Canvas canvas, View child, long drawingTime) {
        try {
            return super.drawChild(canvas, child, drawingTime);
        } catch (Throwable e) {
            return false;
        }
    }

    public void notifyDataSetChanged() {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyDataSetChanged();
                }
            }, 50);
        } else {
            getAdapter().notifyDataSetChanged();
        }
    }

    public final void notifyItemChanged(final int position) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemChanged(position);
                }
            }, 50);
        } else {
            getAdapter().notifyItemChanged(position);
        }
    }

    public final void notifyItemChanged(final int position, final @Nullable Object payload) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemChanged(position, payload);
                }
            }, 50);
        } else {
            getAdapter().notifyItemChanged(position, payload);
        }
    }

    public void notifyItemRangeChanged(final int positionStart, final int itemCount) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemRangeChanged(positionStart, itemCount);
                }
            }, 50);
        } else {
            getAdapter().notifyItemRangeChanged(positionStart, itemCount);
        }
    }

    public final void notifyItemRangeChanged(final int positionStart, final int itemCount, final @Nullable Object payload) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemRangeChanged(positionStart, itemCount, payload);
                }
            }, 50);
        } else {
            getAdapter().notifyItemRangeChanged(positionStart, itemCount, payload);
        }
    }

    public final void notifyItemInserted(final int position) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemInserted(position);
                }
            }, 50);
        } else {
            getAdapter().notifyItemInserted(position);
        }
    }

    public void notifyItemRangeInserted(final int positionStart, final int itemCount) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemRangeInserted(positionStart, itemCount);
                }
            }, 50);
        } else {
            getAdapter().notifyItemRangeInserted(positionStart, itemCount);
        }
    }

    public final void notifyItemRemoved(final int position) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemRemoved(position);
                }
            }, 50);
        } else {
            getAdapter().notifyItemRemoved(position);
        }
    }

    public void notifyItemRangeRemoved(final int positionStart, final int itemCount) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemRangeRemoved(positionStart, itemCount);
                }
            }, 50);
        } else {
            getAdapter().notifyItemRangeRemoved(positionStart, itemCount);
        }
    }

    public void notifyItemMoved(final int fromPosition, final int toPosition) {
        if (getAdapter() == null || getLayoutManager() == null) {
            return;
        }
        if (!assertNotInLayoutOrScroll()) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemMoved(fromPosition, toPosition);
                }
            }, 50);
        } else {
            getAdapter().notifyItemMoved(fromPosition, toPosition);
        }
    }

    private boolean assertNotInLayoutOrScroll() {
        try {
            getLayoutManager().assertNotInLayoutOrScroll(null);
            return true;
        } catch (IllegalStateException e) {
            return false;
        }
    }

    @Override
    public int computeVerticalScrollOffset() {
        try {
            return super.computeVerticalScrollOffset();
        } catch (Throwable e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    public ViewHolder getChildViewHolder(@NonNull View child) {
        try {
            return super.getChildViewHolder(child);
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }
}
